Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
The z-schema npm package is a JSON Schema validator that is compliant with the latest JSON Schema standards. It allows users to validate JSON data against a schema to ensure it meets certain criteria before processing it. This can be particularly useful for validating configuration files, API request payloads, and any other JSON data that requires validation against a predefined structure.
Validation of JSON data
This feature allows you to validate JSON data against a JSON Schema. The code sample demonstrates how to create a new ZSchema validator instance, define a schema, and validate data against that schema.
{"var ZSchema = require('z-schema');
var validator = new ZSchema();
var schema = {"type": "object","properties": {"name": {"type": "string"}}};
var data = {"name": "John Doe"};
validator.validate(data, schema, function(err, valid) {console.log(valid);});}
Custom format validators
Z-schema allows you to define custom formats for data validation. In this code sample, a custom format called 'custom-format' is defined and used in a schema to validate a string.
{"var ZSchema = require('z-schema');
var validator = new ZSchema();
validator.setFormat('custom-format', function(str) {return str === 'custom';});
var schema = {"type": "string","format": "custom-format"};
var data = 'custom';
validator.validate(data, schema, function(err, valid) {console.log(valid);});}
Asynchronous validation
Z-schema supports asynchronous validation using promises. This code sample shows how to validate data against a schema asynchronously.
{"var ZSchema = require('z-schema');
var validator = new ZSchema();
var schema = {"type": "object","properties": {"name": {"type": "string"}}};
var data = {"name": "John Doe"};
validator.validate(data, schema).then(function(valid) {console.log(valid);}).catch(function(err) {console.error(err);});}
Remote references
Z-schema can handle remote references in schemas. This code sample demonstrates how to set up a validator with a remote reference and validate data against it.
{"var ZSchema = require('z-schema');
var validator = new ZSchema({remoteReferences: {"http://my.site/myschema.json": {"type": "object"}}});
var schema = {"$ref": "http://my.site/myschema.json"};
var data = {"name": "John Doe"};
validator.validate(data, schema, function(err, valid) {console.log(valid);});}
Ajv is a fast JSON Schema validator that supports draft-06/07/2019-09 JSON Schema standards. It is known for its performance and is often used in projects that require high-speed validation. Compared to z-schema, Ajv may offer better performance and more up-to-date standards support.
Tiny Validator (tv4) is a small and fast JSON Schema validator that supports draft-04 of the JSON Schema. It is simpler and has a smaller footprint than z-schema, making it suitable for environments with limited resources or where a simple validation solution is needed.
The jsonschema package is another validator for JSON Schema that supports various schema versions. It is designed to be easy to use and extend, with a straightforward API. While z-schema is focused on compliance with the standards, jsonschema emphasizes ease of use and extensibility.
Validator will try to perform sync validation when possible for speed, but supports async callbacks when they are necessary.
These repository has several submodules and should be cloned as follows:
git clone --recursive https://github.com/zaggino/z-schema.git
npm install --global z-schema
z-schema --help
z-schema mySchema.json
z-schema mySchema.json myJson.json
z-schema --strictMode mySchema.json myJson.json
var ZSchema = require("z-schema");
var options = ... // see below for possible option values
var validator = new ZSchema(options);
var valid = validator.validate(json, schema);
// this will return a native error object with name and message
var error = validator.getLastError();
// this will return an array of validation errors encountered
var errors = validator.getLastErrors();
...
validator.validate(json, schema, function (err, valid) {
...
});
<script type="text/javascript" src="../dist/ZSchema-browser-min.js"></script>
<script type="text/javascript">
var validator = new ZSchema();
var valid = validator.validate("string", { "type": "string" });
console.log(valid);
</script>
In case you have some remote references in your schemas, you have to download those schemas before using validator.
Otherwise you'll get UNRESOLVABLE_REFERENCE
error when trying to compile a schema.
var validator = new ZSchema();
var json = {};
var schema = { "$ref": "http://json-schema.org/draft-04/schema#" };
var valid = validator.validate(json, schema);
var errors = validator.getLastErrors();
// valid === false
// errors.length === 1
// errors[0].code === "UNRESOLVABLE_REFERENCE"
var requiredUrl = "http://json-schema.org/draft-04/schema";
request(requiredUrl, function (error, response, body) {
validator.setRemoteReference(requiredUrl, JSON.parse(body));
var valid = validator.validate(json, schema);
var errors = validator.getLastErrors();
// valid === true
// errors === undefined
}
If you're able to load schemas synchronously, you can use ZSchema.setSchemaReader
feature:
ZSchema.setSchemaReader(function (uri) {
var someFilename = path.resolve(__dirname, "..", "schemas", uri + ".json");
return JSON.parse(fs.readFileSync(someFilename, "utf8"));
});
In case you don't want to split your schema into multiple schemas using reference for any reason, you can use option schemaPath when validating:
var valid = validator.validate(cars, schema, { schemaPath: "definitions.car.definitions.cars" });
See more details in the test.
You can use validator to compile an array of schemas that have references between them and then validate against one of those schemas:
var schemas = [
{
id: "personDetails",
type: "object",
properties: {
firstName: { type: "string" },
lastName: { type: "string" }
},
required: ["firstName", "lastName"]
},
{
id: "addressDetails",
type: "object",
properties: {
street: { type: "string" },
city: { type: "string" }
},
required: ["street", "city"]
},
{
id: "personWithAddress",
allOf: [
{ $ref: "personDetails" },
{ $ref: "addressDetails" }
]
}
];
var data = {
firstName: "Martin",
lastName: "Zagora",
street: "George St",
city: "Sydney"
};
var validator = new ZSchema();
// compile & validate schemas first, z-schema will automatically handle array
var allSchemasValid = validator.validateSchema(schemas);
// allSchemasValid === true
// now validate our data against the last schema
var valid = validator.validate(data, schemas[2]);
// valid === true
You can register any format of your own. Your sync validator function should always respond with a boolean:
ZSchema.registerFormat("xstring", function (str) {
return str === "xxx";
});
Async format validators are also supported, they should accept two arguments, value and a callback to which they need to respond:
ZSchema.registerFormat("xstring", function (str, callback) {
setTimeout(function () {
callback(str === "xxx");
}, 1);
});
var registeredFormats = ZSchema.getRegisteredFormats();
//registeredFormats will now contain an array of all formats that have been registered with z-schema
Automatic downloading of remote schemas was removed from version 3.x
but is still possible with a bit of extra code,
see this test for more information on this.
Using format, you can pre-fill values of your choosing into the objects like this:
ZSchema.registerFormat("fillHello", function (obj) {
obj.hello = "world";
return true;
});
var data = {};
var schema = {
"type": "object",
"format": "fillHello"
};
validator.validate(data, schema);
// data.hello === "world"
Defines a time limit, which should be used when waiting for async tasks like async format validators to perform their validation,
before the validation fails with an ASYNC_TIMEOUT
error.
var validator = new ZSchema({
asyncTimeout: 2000
});
When true, validator will assume that minimum count of items in any array
is 1, except when minItems: 0
is explicitly defined.
var validator = new ZSchema({
noEmptyArrays: true
});
When true, validator will assume that minimum length of any string to pass type string
validation is 1, except when minLength: 0
is explicitly defined.
var validator = new ZSchema({
noEmptyStrings: true
});
When true, validator will fail validation for schemas that don't specify a type
of object that they expect.
var validator = new ZSchema({
noTypeless: true
});
When true, validator will fail for schemas that use keywords not defined in JSON Schema specification and doesn't provide a parent schema in $schema
property to validate the schema.
var validator = new ZSchema({
noExtraKeywords: true
});
When true, validator assumes that additionalItems/additionalProperties are defined as false so you don't have to manually fix all your schemas.
var validator = new ZSchema({
assumeAdditional: true
});
When an array, validator assumes that additionalItems/additionalProperties are defined as false, but allows some properties to pass.
var validator = new ZSchema({
assumeAdditional: ["$ref"]
});
When true, validator doesn't validate schemas where additionalItems/additionalProperties should be defined to either true or false.
var validator = new ZSchema({
forceAdditional: true
});
When true, validator doesn't validate schemas where items
are not defined for array
type schemas.
This is to avoid passing anything through an array definition.
var validator = new ZSchema({
forceItems: true
});
When true, validator doesn't validate schemas where minItems
is not defined for array
type schemas.
This is to avoid passing zero-length arrays which application doesn't expect to handle.
var validator = new ZSchema({
forceMinItems: true
});
When true, validator doesn't validate schemas where maxItems
is not defined for array
type schemas.
This is to avoid passing arrays with unlimited count of elements which application doesn't expect to handle.
var validator = new ZSchema({
forceMaxItems: true
});
When true, validator doesn't validate schemas where minLength
is not defined for string
type schemas.
This is to avoid passing zero-length strings which application doesn't expect to handle.
var validator = new ZSchema({
forceMinLength: true
});
When true, validator doesn't validate schemas where maxLength
is not defined for string
type schemas.
This is to avoid passing extremly large strings which application doesn't expect to handle.
var validator = new ZSchema({
forceMaxLength: true
});
When true, validator doesn't validate schemas where properties
or patternProperties
is not defined for object
type schemas.
This is to avoid having objects with unexpected properties in application.
var validator = new ZSchema({
forceProperties: true
});
When true, validator doesn't end with error when a remote reference is unreachable. This setting is not recommended in production outside of testing.
var validator = new ZSchema({
ignoreUnresolvableReferences: true
});
When true, validator will return a ENUM_CASE_MISMATCH
when the enum values mismatch only in case.
var validator = new ZSchema({
enumCaseInsensitiveComparison: true
});
When true, all strings of format uri
must be an absolute URIs and not only URI references. See more details in this issue.
var validator = new ZSchema({
strictUris: true
});
Strict mode of z-schema is currently equal to the following:
if (this.options.strictMode === true) {
this.options.forceAdditional = true;
this.options.forceItems = true;
this.options.forceMaxLength = true;
this.options.forceProperties = true;
this.options.noExtraKeywords = true;
this.options.noTypeless = true;
this.options.noEmptyStrings = true;
this.options.noEmptyArrays = true;
}
var validator = new ZSchema({
strictMode: true
});
By default, z-schema stops validation after the first error is found. With this you can tell it to continue validating anyway:
var validator = new ZSchema({
breakOnFirstError: false
});
Report error paths as an array of path segments instead of a string:
var validator = new ZSchema({
reportPathAsArray: true
});
By default, z-schema reports all unknown formats, formats not defined by JSON Schema and not registered using
ZSchema.registerFormat
, as an error. But the
JSON Schema specification says that validator
implementations "they SHOULD offer an option to disable validation" for format
. That being said, setting this
option to true
will disable treating unknown formats as errlrs
var validator = new ZSchema({
ignoreUnknownFormats: true
});
Warning: Use only if know what you are doing. Always consider using custom format before using this option.
Register function to be called as part of validation process on every subshema encounter during validation.
Let's make a real-life example with this feature. Imagine you have number of transactions:
{
"fromId": 1034834329,
"toId": 1034834543,
"amount": 200
}
So you write the schema:
{
"type": "object",
"properties": {
"fromId": {
"type": "integer"
},
"toId": {
"type": "integer"
},
"amount": {
"type": "number"
}
}
}
But how to check that fromId
and toId
are never equal.
In JSON Schema Draft4 there is no possibility to do this.
Actually, it's easy to just write validation code for such simple payloads.
But what if you have to do the same check for many objects in different places of JSON payload.
One solution is to add custom keyword uniqueProperties
with array of property names as a value. So in our schema we would need to add:
"uniqueProperties": [
"fromId",
"toId"
]
To teach z-schema
about this new keyword we need to write handler for it:
function customValidatorFn(report, schema, json) {
// check if our custom property is present
if (Array.isArray(schema.uniqueProperties)) {
var seenValues = [];
schema.uniqueProperties.forEach(function (prop) {
var value = json[prop];
if (typeof value !== 'undefined') {
if (seenValues.indexOf(value) !== -1) {
// report error back to z-schema core
report.addCustomError("NON_UNIQUE_PROPERTY_VALUE",
"Property \"{0}\" has non-unique value: {1}",
[prop, value], null, schema.description);
}
seenValues.push(value)
}
});
}
}
var validator = new ZSchema({
// register our custom validator inside z-schema
customValidator: customValidatorFn
});
Let's test it:
var data = {
fromId: 1034834346,
toId: 1034834346,
amount: 50
};
validator.validate(data, schema);
console.log(validator.getLastErrors())
//[ { code: 'NON_UNIQUE_PROPERTY_VALUE',
// params: [ 'toId', 1034834346 ],
// message: 'Property "toId" has non-unique value: 1034834346',
// path: '#/',
// schemaId: undefined } ]
Note: before creating your own keywords you should consider all compatibility issues.
So how does it compare to version 2.x and others?
NOTE: these tests are purely orientational, they don't consider extra features any of the validator may support and implement
rawgithub.com/zaggino/z-schema/master/benchmark/results.html
Thanks for contributing to:
and to everyone submitting issues on GitHub
FAQs
JSON schema validator
The npm package z-schema receives a total of 1,913,991 weekly downloads. As such, z-schema popularity was classified as popular.
We found that z-schema demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.